
#
# Ֆակտորիալի հաշվարկը իտերատիվ եղանակով
#
proc factorial_a num {
  set res 1
  for {set k 1} {$k <= $num} {incr k} { 
    set res [expr {$res * $k}]
  }
  return $res
}

#
# Ֆակտորիալի հաշվարկը պարզ ռեկուրսիվ եղանակով
#
proc factorial_b num {
  if {$num == 1} { return 1 }
  return [expr {$num * [factorial_b [expr {$num - 1}]]}]
}

#
# Ֆակտորիալի հաշվարկը կուտակիչով ռեկուրսիայի եղանակով
#
proc factorial_c num {
  proc factorial_h { c m r } {
    if {$c > $m} { return $r }
    return [factorial_h [expr {$c + 1}] $m [expr {$r * $c}]]
  }

  set res [factorial_h 1 $num 1]
  rename factorial_h {}

  return $res
}

#
#
#
proc search_number_between { b_lower b_upper } {
  set middle [expr {int(($b_lower + $b_upper) / 2.0)}]
  puts "Did you think: $middle"
  set ans [gets stdin]
  switch $ans {
    "Yes" {
      puts "Game over."
      return 1
    }
    ">" {
      return [search_number_between $b_lower $middle]
    }
    "<" {
      return [search_number_between $middle $b_upper]
    }
  }
}

#
#
#
proc number_guessing_game range {
  puts "Think an integer between 0 and $range.\n"
  after 4000
  return [search_number_between 0 $range]
}

#
#
#
proc gcd_a { n m } {
  if {$m == 0} { return $n }
  return [gcd_a $m [expr {$n % $m}]]
}

#
#
#
proc gcd_b { n m } {
  while {$n != $m} {
    if {$n > $m} then {
      set n [expr {$n - $m}]
    } else {
      set m [expr {$m - $n}]
    }
  }
  return $n
}

#
#
#
proc monte_carlo_method { f a {n 100} } {
  set no 0
  for {set i 0} {$i < $n} {incr i} {
    set x [expr {rand() * $a}]
    set y [expr {rand() * $a}]
    incr no [expr {[apply $f $x $y] ? 1 : 0}]
  }
  return [expr {($a * $a * $no) / (1.0 * $n)}]
}

proc func name {
  return [list [info args $name] [info body $name]]
}

#
#
#
proc is_in_circle { x y } {
  set a [expr {$x - 1.0}]
  set b [expr {$y - 1.0}]
  return [expr {(($a * $a) + ($b * $b)) <= 1.0}]
}

puts [expr {4.0 * [monte_carlo_method [func is_in_circle] 1.0 1000]}]

#
#
#
proc is_prime num {
  if {$num <= 1} { return false }
  if {$num % 2 == 0} { return false }
  for {set i 2} {$i < [expr {ceil(sqrt($num))}]} {incr i} {
    if {$num % $i == 0} { return false }
  }
  return true
}

#
#
#
proc sum_of_divisors num {
  set res 0
  for {set i 0} {$i < [expr {$num / 2}]} {incr i} {
    if {$num % $i == 0} { incr res $i }
  }
  return $res
}

#
#
#
proc sum_of_divisors_rec num {
  proc f { a k } {
    if {$k <= 1} then { return 1 }
    set m [f $a [expr {$k - 1}]]
    if {0 == $a % $k} then { return [expr {$k + $m}] }
    return $m
  }

  set res [f $num [expr {floor($num / 2)}]]
  rename f {}
  return $res
}



